package com.xyxy.platform.modules.core.spring;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 国际化资源文件
 *
 * @author caizhengda
 * @version [版本号, 2016-05-30]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class ResourceUtil extends ResourceBundleMessageSource {

    protected static final Logger logger = LoggerFactory.getLogger(ResourceUtil.class);

    private static final String REQUEST_LOCALE_HEADER = "X-Client-Language";

    private static Locale defaultLocale = new Locale("zh", "CN");

    private static final String LOCAL_KEY = "result.code.";

    private static final ThreadLocal<Locale> LOCALE_STORE = new InheritableThreadLocal<Locale>();//配合spring mvc 拦截器使用

    private static final ResourceUtil instance = new ResourceUtil();

    public static final String KEY_SEPARATOR = "_";

    private ResourceUtil() {
    }

    public static ResourceUtil getInstance() {
        return instance;
    }

    /**
     * 获取之指定key的资源描述字符
     * <p>
     * 支持MessageFormat,例如：<br>
     * code: <i>getMessage("USER_NOT_EXIST" , "admin");</i><br>
     * properties:<i>USER_NOT_EXIST = user {0} not exist!</i>
     * </p>
     *
     * @param key
     * @param args
     * @return
     */
    public static String getMessage(String key, Object... args) {
        Locale locale = getLocaleObject();
        try {
            return instance.getMessage(key, args, locale);
        } catch (NoSuchMessageException e) {
            return key;
        }
    }

    /**
     * 获取返回码指定的资源值
     *
     * @param code
     * @return
     */
    public static String getMessage(int code, Object... args) {
        return getMessage(LOCAL_KEY + code, args);
    }

    public static void setLocale(HttpServletRequest request) {
        String locale = request.getHeader(REQUEST_LOCALE_HEADER);
        setLocale(locale);
    }

    /**
     * 设置当前处理线程的 locale
     *
     * @param localeStr
     */
    public static void setLocale(String localeStr) {
        if (StringUtils.isBlank(localeStr)) return;
        Locale locale;
        // 兼容语言和国家的连接符号
        int splitIndex = localeStr.indexOf('_');
        if (splitIndex < 0) {
            splitIndex = localeStr.indexOf('-');
        }
        if (splitIndex < 0) {
            locale = new Locale(localeStr.toLowerCase());
        } else {
            locale = new Locale(localeStr.substring(0, splitIndex).toLowerCase(),
                    localeStr.substring(splitIndex + 1).toUpperCase());
        }
        setLocale(locale);
    }

    public static void setLocale(Locale locale) {
        LOCALE_STORE.set(locale);
    }

    /**
     * 获取本地化字符串
     *
     * @return
     */
    public static String getLocale() {
        if ("zh_HANS_CN".equals(getLocaleObject().toString())) {
            return "zh_CN";
        } else {
            return getLocaleObject().toString();
        }
    }

    /**
     * 获取本地化字符串 前缀
     *
     * @return
     */
    public static String getLocaleKey() {
        return getLocale() + KEY_SEPARATOR;
    }

    /**
     * 获取本地化对象
     *
     * @return
     */
    public static Locale getLocaleObject() {
        Locale l = LOCALE_STORE.get();
        if (l == null) {
            LOCALE_STORE.set(l = defaultLocale);
        }
        return l;
    }

    public static void clearLocale() {
        LOCALE_STORE.remove();
    }

    /**
     * 资源文件扩展名
     */
    public final static String PROPERTY_POSTFIX = ".properties";

    /**
     * 资源文件头
     */
    public final static String PROPERTY_POSTFIX_PATH = "properties.";

    private PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.context.support.ResourceBundleMessageSource#setBasenames(java.lang.String[])
     */
    @Override
    public void setBasenames(String[] baseNames) {
        try {
            String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();

            List<String> baseNameList = new ArrayList<String>();
            for (String baseName : baseNames) {
                // 根据通配符获取资源对象集合
                Resource[] resources = patternResolver.getResources(baseName); // 通过通配符取得到所有对应的source

                for (Resource resource : resources) {
                    if (resource.getURL().toString().startsWith("jar:")
                            && resource.getURL().toString().indexOf("!/") != -1) {
                        String filePath = resource.getURL()
                                .toString()
                                .substring(resource.getURL().toString().indexOf("!/") + 2);
                        String _baseName = filePath.substring(0, filePath.indexOf(PROPERTY_POSTFIX)).replaceAll("/",
                                ".");

                        if (_baseName.contains("_")) {
                            _baseName = _baseName.substring(0, _baseName.indexOf("_"));
                        }

                        baseNameList.add(_baseName);
                    } else {
                        String fileName = resource.getURL().getPath();
                        String _baseName = fileName.substring(basePath.length(), fileName.indexOf(PROPERTY_POSTFIX))
                                .replaceAll("/", ".");

                        if (_baseName.contains("_")) {
                            _baseName = _baseName.substring(0, _baseName.indexOf("_"));
                        }

                        baseNameList.add(_baseName);
                    }
                }
            }
            if (!baseNameList.isEmpty()) {
                super.setBasenames((String[]) baseNameList.toArray(new String[baseNameList.size()]));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void setDefaultLocale(Locale locale) {
        defaultLocale = locale;
    }

    public static Locale getDefaultLocale() {
        return defaultLocale;
    }

}
